home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / perl / 5.10.0 / IPC / Open3.pm < prev   
Encoding:
Perl POD Document  |  2009-06-26  |  7.6 KB  |  275 lines

  1. package IPC::Open3;
  2.  
  3. use strict;
  4. no strict 'refs'; # because users pass me bareword filehandles
  5. our ($VERSION, @ISA, @EXPORT);
  6.  
  7. require Exporter;
  8.  
  9. use Carp;
  10. use Symbol qw(gensym qualify);
  11.  
  12. $VERSION    = 1.02;
  13. @ISA        = qw(Exporter);
  14. @EXPORT        = qw(open3);
  15.  
  16. # &open3: Marc Horowitz <marc@mit.edu>
  17. # derived mostly from &open2 by tom christiansen, <tchrist@convex.com>
  18. # fixed for 5.001 by Ulrich Kunitz <kunitz@mai-koeln.com>
  19. # ported to Win32 by Ron Schmidt, Merrill Lynch almost ended my career
  20. # fixed for autovivving FHs, tchrist again
  21. # allow fd numbers to be used, by Frank Tobin
  22. # allow '-' as command (c.f. open "-|"), by Adam Spiers <perl@adamspiers.org>
  23. #
  24. # $Id: open3.pl,v 1.1 1993/11/23 06:26:15 marc Exp $
  25. #
  26. # usage: $pid = open3('wtr', 'rdr', 'err' 'some cmd and args', 'optarg', ...);
  27. #
  28. # spawn the given $cmd and connect rdr for
  29. # reading, wtr for writing, and err for errors.
  30. # if err is '', or the same as rdr, then stdout and
  31. # stderr of the child are on the same fh.  returns pid
  32. # of child (or dies on failure).
  33.  
  34. # if wtr begins with '<&', then wtr will be closed in the parent, and
  35. # the child will read from it directly.  if rdr or err begins with
  36. # '>&', then the child will send output directly to that fd.  In both
  37. # cases, there will be a dup() instead of a pipe() made.
  38.  
  39. # WARNING: this is dangerous, as you may block forever
  40. # unless you are very careful.
  41. #
  42. # $wtr is left unbuffered.
  43. #
  44. # abort program if
  45. #   rdr or wtr are null
  46. #   a system call fails
  47.  
  48. our $Me = 'open3 (bug)';    # you should never see this, it's always localized
  49.  
  50. # Fatal.pm needs to be fixed WRT prototypes.
  51.  
  52. sub xfork {
  53.     my $pid = fork;
  54.     defined $pid or croak "$Me: fork failed: $!";
  55.     return $pid;
  56. }
  57.  
  58. sub xpipe {
  59.     pipe $_[0], $_[1] or croak "$Me: pipe($_[0], $_[1]) failed: $!";
  60. }
  61.  
  62. # I tried using a * prototype character for the filehandle but it still
  63. # disallows a bearword while compiling under strict subs.
  64.  
  65. sub xopen {
  66.     open $_[0], $_[1] or croak "$Me: open($_[0], $_[1]) failed: $!";
  67. }
  68.  
  69. sub xclose {
  70.     close $_[0] or croak "$Me: close($_[0]) failed: $!";
  71. }
  72.  
  73. sub fh_is_fd {
  74.     return $_[0] =~ /\A=?(\d+)\z/;
  75. }
  76.  
  77. sub xfileno {
  78.     return $1 if $_[0] =~ /\A=?(\d+)\z/;  # deal with fh just being an fd
  79.     return fileno $_[0];
  80. }
  81.  
  82. my $do_spawn = $^O eq 'os2' || $^O eq 'MSWin32';
  83.  
  84. sub _open3 {
  85.     local $Me = shift;
  86.     my($package, $dad_wtr, $dad_rdr, $dad_err, @cmd) = @_;
  87.     my($dup_wtr, $dup_rdr, $dup_err, $kidpid);
  88.  
  89.     if (@cmd > 1 and $cmd[0] eq '-') {
  90.     croak "Arguments don't make sense when the command is '-'"
  91.     }
  92.  
  93.     # simulate autovivification of filehandles because
  94.     # it's too ugly to use @_ throughout to make perl do it for us
  95.     # tchrist 5-Mar-00
  96.  
  97.     unless (eval  {
  98.     $dad_wtr = $_[1] = gensym unless defined $dad_wtr && length $dad_wtr;
  99.     $dad_rdr = $_[2] = gensym unless defined $dad_rdr && length $dad_rdr;
  100.     1; }) 
  101.     {
  102.     # must strip crud for croak to add back, or looks ugly
  103.     $@ =~ s/(?<=value attempted) at .*//s;
  104.     croak "$Me: $@";
  105.     } 
  106.  
  107.     $dad_err ||= $dad_rdr;
  108.  
  109.     $dup_wtr = ($dad_wtr =~ s/^[<>]&//);
  110.     $dup_rdr = ($dad_rdr =~ s/^[<>]&//);
  111.     $dup_err = ($dad_err =~ s/^[<>]&//);
  112.  
  113.     # force unqualified filehandles into caller's package
  114.     $dad_wtr = qualify $dad_wtr, $package unless fh_is_fd($dad_wtr);
  115.     $dad_rdr = qualify $dad_rdr, $package unless fh_is_fd($dad_rdr);
  116.     $dad_err = qualify $dad_err, $package unless fh_is_fd($dad_err);
  117.  
  118.     my $kid_rdr = gensym;
  119.     my $kid_wtr = gensym;
  120.     my $kid_err = gensym;
  121.  
  122.     xpipe $kid_rdr, $dad_wtr if !$dup_wtr;
  123.     xpipe $dad_rdr, $kid_wtr if !$dup_rdr;
  124.     xpipe $dad_err, $kid_err if !$dup_err && $dad_err ne $dad_rdr;
  125.  
  126.     $kidpid = $do_spawn ? -1 : xfork;
  127.     if ($kidpid == 0) {        # Kid
  128.     # A tie in the parent should not be allowed to cause problems.
  129.     untie *STDIN;
  130.     untie *STDOUT;
  131.     # If she wants to dup the kid's stderr onto her stdout I need to
  132.     # save a copy of her stdout before I put something else there.
  133.     if ($dad_rdr ne $dad_err && $dup_err
  134.         && xfileno($dad_err) == fileno(STDOUT)) {
  135.         my $tmp = gensym;
  136.         xopen($tmp, ">&$dad_err");
  137.         $dad_err = $tmp;
  138.     }
  139.  
  140.     if ($dup_wtr) {
  141.         xopen \*STDIN,  "<&$dad_wtr" if fileno(STDIN) != xfileno($dad_wtr);
  142.     } else {
  143.         xclose $dad_wtr;
  144.         xopen \*STDIN,  "<&=" . fileno $kid_rdr;
  145.     }
  146.     if ($dup_rdr) {
  147.         xopen \*STDOUT, ">&$dad_rdr" if fileno(STDOUT) != xfileno($dad_rdr);
  148.     } else {
  149.         xclose $dad_rdr;
  150.         xopen \*STDOUT, ">&=" . fileno $kid_wtr;
  151.     }
  152.     if ($dad_rdr ne $dad_err) {
  153.         if ($dup_err) {
  154.         # I have to use a fileno here because in this one case
  155.         # I'm doing a dup but the filehandle might be a reference
  156.         # (from the special case above).
  157.         xopen \*STDERR, ">&" . xfileno($dad_err)
  158.             if fileno(STDERR) != xfileno($dad_err);
  159.         } else {
  160.         xclose $dad_err;
  161.         xopen \*STDERR, ">&=" . fileno $kid_err;
  162.         }
  163.     } else {
  164.         xopen \*STDERR, ">&STDOUT" if fileno(STDERR) != fileno(STDOUT);
  165.     }
  166.     return 0 if ($cmd[0] eq '-');
  167.     local($")=(" ");
  168.     exec @cmd or do {
  169.         carp "$Me: exec of @cmd failed";
  170.         eval { require POSIX; POSIX::_exit(255); };
  171.         exit 255;
  172.     };
  173.     } elsif ($do_spawn) {
  174.     # All the bookkeeping of coincidence between handles is
  175.     # handled in spawn_with_handles.
  176.  
  177.     my @close;
  178.     if ($dup_wtr) {
  179.       $kid_rdr = \*{$dad_wtr};
  180.       push @close, $kid_rdr;
  181.     } else {
  182.       push @close, \*{$dad_wtr}, $kid_rdr;
  183.     }
  184.     if ($dup_rdr) {
  185.       $kid_wtr = \*{$dad_rdr};
  186.       push @close, $kid_wtr;
  187.     } else {
  188.       push @close, \*{$dad_rdr}, $kid_wtr;
  189.     }
  190.     if ($dad_rdr ne $dad_err) {
  191.         if ($dup_err) {
  192.           $kid_err = \*{$dad_err};
  193.           push @close, $kid_err;
  194.         } else {
  195.           push @close, \*{$dad_err}, $kid_err;
  196.         }
  197.     } else {
  198.       $kid_err = $kid_wtr;
  199.     }
  200.     require IO::Pipe;
  201.     $kidpid = eval {
  202.         spawn_with_handles( [ { mode => 'r',
  203.                     open_as => $kid_rdr,
  204.                     handle => \*STDIN },
  205.                   { mode => 'w',
  206.                     open_as => $kid_wtr,
  207.                     handle => \*STDOUT },
  208.                   { mode => 'w',
  209.                     open_as => $kid_err,
  210.                     handle => \*STDERR },
  211.                 ], \@close, @cmd);
  212.     };
  213.     die "$Me: $@" if $@;
  214.     }
  215.  
  216.     xclose $kid_rdr if !$dup_wtr;
  217.     xclose $kid_wtr if !$dup_rdr;
  218.     xclose $kid_err if !$dup_err && $dad_rdr ne $dad_err;
  219.     # If the write handle is a dup give it away entirely, close my copy
  220.     # of it.
  221.     xclose $dad_wtr if $dup_wtr;
  222.  
  223.     select((select($dad_wtr), $| = 1)[0]); # unbuffer pipe
  224.     $kidpid;
  225. }
  226.  
  227. sub open3 {
  228.     if (@_ < 4) {
  229.     local $" = ', ';
  230.     croak "open3(@_): not enough arguments";
  231.     }
  232.     return _open3 'open3', scalar caller, @_
  233. }
  234.  
  235. sub spawn_with_handles {
  236.     my $fds = shift;        # Fields: handle, mode, open_as
  237.     my $close_in_child = shift;
  238.     my ($fd, $pid, @saved_fh, $saved, %saved, @errs);
  239.     require Fcntl;
  240.  
  241.     foreach $fd (@$fds) {
  242.     $fd->{tmp_copy} = IO::Handle->new_from_fd($fd->{handle}, $fd->{mode});
  243.     $saved{fileno $fd->{handle}} = $fd->{tmp_copy};
  244.     }
  245.     foreach $fd (@$fds) {
  246.     bless $fd->{handle}, 'IO::Handle'
  247.         unless eval { $fd->{handle}->isa('IO::Handle') } ;
  248.     # If some of handles to redirect-to coincide with handles to
  249.     # redirect, we need to use saved variants:
  250.     $fd->{handle}->fdopen($saved{fileno $fd->{open_as}} || $fd->{open_as},
  251.                   $fd->{mode});
  252.     }
  253.     unless ($^O eq 'MSWin32') {
  254.     # Stderr may be redirected below, so we save the err text:
  255.     foreach $fd (@$close_in_child) {
  256.         fcntl($fd, Fcntl::F_SETFD(), 1) or push @errs, "fcntl $fd: $!"
  257.         unless $saved{fileno $fd}; # Do not close what we redirect!
  258.     }
  259.     }
  260.  
  261.     unless (@errs) {
  262.     $pid = eval { system 1, @_ }; # 1 == P_NOWAIT
  263.     push @errs, "IO::Pipe: Can't spawn-NOWAIT: $!" if !$pid || $pid < 0;
  264.     }
  265.  
  266.     foreach $fd (@$fds) {
  267.     $fd->{handle}->fdopen($fd->{tmp_copy}, $fd->{mode});
  268.     $fd->{tmp_copy}->close or croak "Can't close: $!";
  269.     }
  270.     croak join "\n", @errs if @errs;
  271.     return $pid;
  272. }
  273.  
  274. 1; # so require is happy
  275.